package com.zc.util;

import java.math.BigDecimal;

import static com.zc.util.ModbusCRC16.calculateCRC;

/**
 * @ClassName RadixUtil
 * @Description
 * @Author GaoGuangChao
 * @Date 2019/5/17 10:00
 * @Version V1.0
 **/
public class RadixUtil {
    private RadixUtil() {

    }


    /**
     * 计算两个二进制数之和
        循环遍历两个字符串，循环一直到遍历完长度更长的串
        模拟竖式相加的过程
        每次竖式相加的过程都是-> 进位 + 上面数字 + 下面数字
        如果短串先遍历完了，就只加长串
        相加之后当前位的结果可以用 相加之和除2取余表示
    */
    public static String addBinary(String a, String b) {
        int aIndex = a.length() - 1, bIndex = b.length() - 1, carry = 0;
        StringBuilder builder = new StringBuilder();
        while (aIndex > -1 || bIndex > -1) {
            if (aIndex > -1)
                carry = carry + a.charAt(aIndex--) - '0';
            if (bIndex > -1)
                carry = carry + b.charAt(bIndex--) - '0';
            builder.append(carry % 2);
            carry = carry / 2; //进位
        }
        //上面循环结束后如果carry == 1，这说明最高位还产生了进位，那么还需要添加一个1
        if (carry == 1)
            builder.append(1);
        return builder.reverse().toString();
    }

    /**
     *  LENGTH数据格式 LCHKSUM 校验码校验
     * @param data LENID(要计算的数据)
     * @return
     */
    public static String LchkSum(String data) {
        //判断需要检测的数据是否为空
        if (data.isEmpty()) {
            return "";
        }
        String one = data.substring(0, 4);
        String two = data.substring(4, 8);
        String three = data.substring(8);
        String s = addBinary(addBinary(one, two), three);
        // 模16
        int mod = Integer.parseInt(s, 2) % 16;
        // 取反+1
        int ret = ~mod + 1;
        String binary =  RadixUtil.hex2Binary( RadixUtil.int2Hex(ret));
        return binary.substring(binary.length() - 4);
    }

    /**
     * 科士达UPS info浮点数解析
     * 16进制数据转浮点数
     * @param str 要转换的16进制数
     * @return 转换完毕的浮点数值
     */
    public static String infoParse(String str) {
        String reverse =  RadixUtil.reverse(str);
        String hexToAscii =  RadixUtil.hexToAscii(reverse);
        String hex2bin =  RadixUtil.hex2Binary(hexToAscii);
        String S = hex2bin.substring(0, 1);
        String E = hex2bin.substring(1, 9);
        String M = hex2bin.substring(9);
        int E2Dec = Integer.parseInt( RadixUtil.hexToDecimal( RadixUtil.binary2Hex(E)));
        int M2Dec = Integer.parseInt( RadixUtil.hexToDecimal( RadixUtil.binary2Hex(M)));
//      浮点数值 = ±（1+M×2^(-23)）·2^(E-127)
        int E_mi = E2Dec - 127;
        double E2 = E_mi > 0 ? 2 : 0.5;
        double pow = Math.pow(E2, Math.abs(E_mi));
        double v = (1 * pow) + M2Dec * Math.pow(0.5, 23) * pow;
        BigDecimal bigDecimal = new BigDecimal(v);
        double v1 = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
//        String format = String.format("%.2f", v1);
        String sum = "1".equals(S) ? "-" + v1 : String.valueOf(v1);
        return sum;
    }


    /*******************************十六进制与二进制的相互转换*********************************/
    /**
     * 将2进制转换为16进制。
     *
     * @param binayString
     * @return
     */
    public static String binary2Hex(String binayString) {
        if (CommonUtil.isNull(binayString))
            return null;
        long result = Long.parseLong(binayString, 2);
        return Long.toHexString(result);
    }


    /**
     * 将16进制转换为2进制
     *
     * @param hexString
     * @return
     */
    public static String hex2Binary(String hexString) {
        if (CommonUtil.isNull(hexString))
            return null;
        long result = Long.parseLong(hexString, 16);
        String hex2 = Long.toBinaryString(result);
        StringBuffer resultHex = new StringBuffer();
        //前面补0
        if (hex2.length() != hexString.length() * 4) {
            for (int i = 0; i < hexString.length() * 4 - hex2.length(); i++) {
                resultHex.append("0");
            }
        }
        resultHex.append(hex2);
        return resultHex.toString();
    }

/*******************************十六进制与byte[]的相互转换*********************************/
    /**
     * 把一个 十六进制的字符串转化成byte数组
     *
     * @param
     * @return
     */
    public static byte[] hexToByte(String str) {
        //把一个十六进制的字符串，转化成String数组(2位)
        String[] hexString = toStringArray(str);
        byte[] result = new byte[hexString.length];
        int count = 0;
        for (String s : hexString) {
            result[count] = ((byte) Integer.parseInt(s, 16));
            count++;
        }
        return result;
    }

    /**
     * 将byte转化为十六进制字符串
     *
     * @param bytes
     * @return
     */
    public static String byte2Hex(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (byte b : bytes) {
            sb.append(String.format("%02x ", b));
        }
        return sb.toString().trim();
    }

    /**
     * 将byte转化为十六进制字符串 长度为1的在前面追加0
     *
     * @param
     * @return
     */
    public static String byte2HexStr(byte[] b) {
        String stmp = "";
        StringBuilder sb = new StringBuilder("");
        for (int n = 0; n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0xFF);
            sb.append((stmp.length() == 1) ? "0" + stmp : stmp);
        }
        return sb.toString().toUpperCase().trim();
    }

    /*************十进制数转为十六位二进制**************/
    public static String dec2Binary(Object dec){
        String string = Integer.toBinaryString(Integer.parseInt(String.valueOf(dec)));
        StringBuilder stringBuilder = new StringBuilder();
        while (string.length() + stringBuilder.length() < 16){
            stringBuilder.append(0);
        }
        return stringBuilder + string;
    }


    /*******************************十六进制与十进制的相互转换*********************************/
    /**
     * 十六进制字符串转换成十进制字符串
     *
     * @param hex
     * @return
     */
    public static String hexToDecimal(String hex) {
        if (hex.startsWith("0x")) {
            return String.valueOf(Integer.parseInt(hex.substring(2), 16));
        } else {
            return String.valueOf(Integer.parseInt(hex, 16));
        }
    }


    /**
     * 将int类型转换为16进制
     *
     * @param number
     * @param byteNumber 转换后的字节数，00为一个字节
     * @return
     */
    public static String int2Hex(int number, int byteNumber) {
        String result = Integer.toHexString(number);
        if (result.length() == 1) {
            if (byteNumber == 2)
                return "00 0" + result;
            return "0" + result;
        }
        if (result.length() == 2) {
            if (byteNumber == 2)
                return "00 " + result;
            return result;
        }
        if (result.length() == 3) {
            if (byteNumber == 1)
                return result.substring(1);
            result = "0" + result;
            return result.substring(0, 2) + " " + result.substring(2);
        }
        if (result.length() == 4) {
            if (byteNumber == 1)
                return result.substring(2);
            return result.substring(0, 2) + " " + result.substring(2);
        }
        if (result.length() > 4) {
            if (byteNumber == 1)
                return result.substring(result.length() - 2);
            return result.substring(result.length() - 4);
        }

        return "";
    }

    /**
     * 将int类型10进制转换为16进制
     *
     * @param number
     * @return
     */
    public static String intHECToHex(int number){
        String hexadecimal = Integer.toHexString(number).toUpperCase(); // 调用toHexString()方法将int型变量转换为十六进制字符串并转为大写形式
        if(hexadecimal.length() % 2 == 1){
            hexadecimal="0"+hexadecimal;
        }
        return hexadecimal;
    }


    /**
     * int类型转换为十六进制
     *
     * @param number
     * @return
     */
    public static String int2Hex(int number) {
        return int2Hex(number, 1);
    }

    /*
     * IEEE 754 标准的  十六进制字符串转单精度浮点数
     * */
    public static String hexToFloat(String datainfo) {
        float value = Float.intBitsToFloat(Long.valueOf(datainfo, 16).intValue());
        String format = String.valueOf(value);
        return format;
    }

    /**
     * fanchao
     * 2020/03/06
     * 十六进制字符串转单精度浮点数  (高低字节转换后的十六进制字符串)
     *
     * @param datainfo
     * @return
     */
    public static String hexStrToFloat(String datainfo) {
        //每两位进行反转
        String result = reverse(datainfo);    //反转字符串
        float value = Float.intBitsToFloat(Integer.valueOf(result, 16));
        String format = String.valueOf(value);
        return format;
    }

    /**
     * 16进制补码转10进制数
     * @param str
     * @return
     */
    public static int complemwnt(String str) {
        int result = 0;
        String binaryString = Integer.toBinaryString(Integer.valueOf(str, 16));
        while(binaryString.length() < 16){
            binaryString = "0"+binaryString;
        }
        String binary = binaryString.substring(0,1);//取第一位判断正负
        if ("0".equals(binary)) {
            result = Integer.valueOf(binaryString,2);
        }else {
            String[] split = binaryString.split("");
            StringBuilder builder = new StringBuilder();
            for (String s : split) {
                if("0".equals(s)){
                    builder.append("1");
                }else {
                    builder.append("0");
                }
            }
            // 调用Integer.valueOf(value, 2) 将二进制转为十进制.
            result = Integer.valueOf(builder.toString(),2);
            // 先取负数在减1
            result = (0 - result) - 1;
        }
        return result;

    }


    /*******************************十六进制与ascii的相互转换*********************************/
    /**
     * 将十六进制文本转化位ascii码
     * 30-->0  31-->1
     *
     * @param
     * @return
     */

    public static String hexToAscii(String hexStr) {
        StringBuilder output = new StringBuilder("");
        for (int i = 0; i < hexStr.length(); i += 2) {
            String str = hexStr.substring(i, i + 2);
            output.append((char) Integer.parseInt(str, 16));
        }
        return output.toString();
    }

    /**
     * ASCII码转换为16进制
     * 0-->30  1-->31
     *
     * @param str
     * @return
     */
    public static String convertStringToHex(String str) {
        char[] chars = str.toCharArray();
        StringBuffer hex = new StringBuffer();
        for (int i = 0; i < chars.length; i++) {
            hex.append(Integer.toHexString((int) chars[i]));
        }
        return hex.toString();
    }


    /**
     * ASCII码转换为字符
     * */
    public static String convertStringToString(String str){
        StringBuffer data=new StringBuffer();
        for (int i = 0; i <str.length() ; i+= 2) {
            String s = hexToDecimal(str.substring(i, i + 2));
            int ascii = Integer.parseInt(s);
            char character = (char) ascii;
            data.append(character);
        }
        return data.toString();
    }

    /*******************************GB2312/GBK码与汉字的相互转换*********************************/
    /**
     * 将汉字的GB2312/GBK码转化为汉字
     *
     * @param str
     * @return
     * @throws Exception
     */
    public static String gb2312ToWord(String str) throws Exception {
        String result = "";
        if (CommonUtil.isNull(str))
            return result;
        str = str.replaceAll(" ", "");
        byte[] bytes = new byte[str.length() / 2];
        for (int i = 0; i < bytes.length; i++) {
            byte high = Byte.parseByte(str.substring(i * 2, i * 2 + 1), 16);
            byte low = Byte.parseByte(str.substring(i * 2 + 1, i * 2 + 2), 16);
            bytes[i] = (byte) (high << 4 | low);
        }
        if (bytes.length > 0) {
            result = new String(bytes, "gbk");
        }

        return result;
    }

    /**
     * 将汉字转化为GB2312/GBK码
     *
     * @param word
     * @return
     * @throws Exception
     */
    public static String wordToGb2312(String word) throws Exception {
        byte[] gb2312 = word.getBytes("GB2312");
        return  RadixUtil.byte2Hex(gb2312);
    }


    /**
     * 把一个十六进制的字符串，转化成String数组(4位)
     *
     * @param str
     * @return
     */
    public static String[] toStringArrayFore(String str) {
        StringBuffer sb = new StringBuffer(str);
        int index;
        for (index = 4; index < sb.length(); index += 5) {
            sb.insert(index, ',');
        }
        return sb.toString().split(",");
    }

    /**
     * 把一个十六进制的字符串，转化成String数组(2位)
     *
     * @param str
     * @return
     */
    public static String[] toStringArray(String str) {
        StringBuffer sb = new StringBuffer(str);
        int index;
        for (index = 2; index < sb.length(); index += 3) {
            sb.insert(index, ',');
        }
        return sb.toString().split(",");
    }

    /**
     * fanchao
     * 2020/03/06
     * 反轉字符串
     * 把一个十六进制的字符串 高低位互换
     *
     * @param s 以字节为单位的数字字符串(不包含0x和空格)
     * @return
     */
    public static String reverse(String s) {
        String reverse = "";
        int i = 0;
        while (i < s.length()) {
            reverse = s.substring(i, i + 2) + reverse;
            i = i + 2;
        }
        return reverse;
    }

    /**
     * bcd码减33H，高低位互换
     *
     * @param s 以字节为单位的数字字符串(不包含0x和空格)
     * @return
     */
    public static String reverseBCD(String s) {
        String reverse = "";
        int i = 0;
        while (i < s.length()) {
            String n=s.substring(i, i + 2);
            int di=Integer.parseInt(hexToDecimal(n));
            String dr=int2Hex(di-51);
            reverse = dr + reverse;
            i = i + 2;
        }
        return reverse;
    }

    /**
     * 16进制转字节。低字节在前、高字节在后
     * @param value
     * @return
     * 0x1000 转换结果0010
     */
    public static byte[] hex2LowHighByte(long value){
        byte a[]=new byte[2];//双字节
        a[0]=(byte)(value&0xff); //获得低位字节
        a[1]=(byte)(value>>>8);//获得高位字节
        return a;
    }

    /**
     * 10进制16进制
     * @param value
     * @return
     */
    public static String decimalToHex(String value) {
        StringBuffer data=new StringBuffer();
        for (int i = 0; i <value.length() ; i=i+2) {
            String substring = value.substring(i, i + 2);
            System.out.println(substring);
            String s = Integer.toHexString(Integer.valueOf(value.substring(i,i+2)));
            if(s.length()<2){
                s="0"+s;
            }
            data.append(s);
        }
        return data.toString();
    }


    /**
     * 充电桩价格8位转换
     * 10进制16进制
     * @param value
     * @return
     */
    public static String eightDecimalToHex(int value) {
        String hexadecimal = Integer.toHexString(value).toUpperCase(); // 调用toHexString()方法将int型变量转换为十六进制字符串并转为大写形式
        if(hexadecimal.length() % 2 == 1){
            hexadecimal="0"+hexadecimal;
        }
        StringBuffer supplement=new StringBuffer();
        for (int i = hexadecimal.length(); i <8 ; i++) {
            supplement.append("0");
        }
        return reverse(supplement.toString()+hexadecimal);
    }

    /**
     * 国轩效验
     * */
    public static String makeChecksum(String data) {
        if (data == null || data.equals("")) {
            return "00";
        }
        data = data.replaceAll(" ", "");
        int total = 0;
        int len = data.length();
        if (len % 2 != 0) {
            return "00";
        }
        int num = 0;
        while (num < len) {
            String s = data.substring(num, num + 2);
            total += Integer.parseInt(s, 16);
            num = num + 2;
        }
        String gentle = Integer.toHexString(total);
        if(gentle.length()==1){
            gentle="0"+gentle;
        }
        return gentle.substring(gentle.length()-2,gentle.length());
    }

    /**
     * 16进制字符串转int数组
     * @param hexString
     * @return
     */
    public static int[] hexStringToIntArray(String hexString) {
        int len = hexString.length();
        int[] intArray = new int[len / 2];
        for (int i = 0; i < len; i += 2) {
            String hexPair = hexString.substring(i, i + 2);
            int intValue = Integer.parseInt(hexPair, 16);
            intArray[i / 2] = intValue;
        }
        return intArray;
    }

    /**
     * 2进制补码 转 十进制
     * 一般用这个 正数在计算机中原码补码相同 负数在计算机中以补码存储  可以理解为都是按照补码存储的
     *11100110   真值-26
     * @param binaryStr 2进制补码
     * @param includeSymbol 是否区分符号位
     * @return
     */
    public static String AddBinToDec(String binaryStr, boolean includeSymbol) {
        String result = "";
        //有符号且符号为1，负数时特殊处理
        if (includeSymbol && binaryStr.charAt(0) == '1') {
            result = negativeBinToDec(binaryStr);
        } else {
            long i = Long.parseLong(binaryStr, 2);
            result = String.valueOf(i);
        }
        return result;
    }


    /**
     * 2进制负数转10进制
     *
     * @param binaryStr
     * @return
     */
    public static String negativeBinToDec(String binaryStr) {
        //获取反码
        String oppositeCode =  getOppositeCode(binaryStr);
        //取反
        String negateBinary  = getNegate(oppositeCode);
        //转十进制带符号
        String result = "-"+Long.parseLong(negateBinary, 2);
        return result;
    }

    /**
     * 补码 -> 反码
     *
     * @param binaryStr
     * @return
     */
    public static String getOppositeCode(String binaryStr) {
        /**
         * 补码减1，得反码；
         * 1.末尾为1，反码：末尾变0，其他位不变
         * 2.末尾为0，
         */
        int down = 0;
        int len = binaryStr.length();
        StringBuffer oppositeCode = new StringBuffer();
        if (binaryStr.charAt(len - 1) == '1') {
            oppositeCode = oppositeCode.append(binaryStr.substring(0, len - 1) + "0");
            return oppositeCode.toString();
        }
        for (int i = len - 1; i >= 0; i--) {
            if (i == len - 1) {
                oppositeCode.append(1);
                down = 1;
                continue;
            }
            int c =  binaryStr.charAt(i);
            c =Character.getNumericValue(c);
            int m = c - down;
            if (m == 0) {
                oppositeCode.append(0);
                down = 0;
                continue;
            }
            if (m == -1) {
                oppositeCode.append(1);
                down = 1;
                continue;
            }
            if (m == 1) {
                oppositeCode.append(1);
                down = 0;
                continue;
            }
        }
        return oppositeCode.reverse().toString();
    }

    /**
     * 取反
     * @return
     */
    public static String getNegate(String binaryStr){
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < binaryStr.length() ; i++){
            if (binaryStr.charAt(i) == '0'){
                sb.append('1');
            }else {
                sb.append('0');
            }
        }
        return sb.toString();
    }


    /**
     * crc16 低字节在前
     * */
    public static String Crc16LowByte(String data){
        byte[] message= hexToByte(data);
        String crcValidation = intHECToHex(calculateCRC(message));
        System.out.println(crcValidation);
        return crcValidation;
    }


















}
